﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections.Specialized;

namespace GACExplorer.Forms
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            try
            {
                InitializeComponent();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            try
            {
                LoadDataGridView();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void RefreshMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                LoadDataGridView();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void FolderLocationMenuItem_Click(object sender, EventArgs e)
        {
            Process newProcess = new Process();
            try
            {
                foreach (DataGridViewRow selectedRow in MainDataGridView.SelectedRows)
                {
                    string assemblyFolderLocation = selectedRow.Cells[FolderLocationColumn.Name].Value.ToString();
                    newProcess.StartInfo.FileName = assemblyFolderLocation;
                    newProcess.Start();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void CopyMenuItem_Click(object sender, EventArgs e)
        {
            StringCollection filePathCollection = new StringCollection();
            try
            {
                foreach (DataGridViewRow selectedRow in MainDataGridView.SelectedRows)
                {
                    string assemblyFileName = selectedRow.Cells[AssemblyNameColumn.Name].Value.ToString();
                    string sourceFileLocation = selectedRow.Cells[FolderLocationColumn.Name].Value.ToString() + Path.DirectorySeparatorChar + assemblyFileName;
                    filePathCollection.Add(sourceFileLocation);
                }

                if (filePathCollection.Count > 0)
                {
                    Clipboard.Clear();
                    Clipboard.SetFileDropList(filePathCollection);
                }

                MessageBox.Show("Successfully copied " + MainDataGridView.SelectedRows.Count + " assembly(s) to clipboard!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void CopySelectedToFolderMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (MainFolderBrowserDialog.ShowDialog() == DialogResult.OK)
                {
                    string targetFolderPath = MainFolderBrowserDialog.SelectedPath;
                    foreach (DataGridViewRow selectedRow in MainDataGridView.SelectedRows)
                    {
                        string assemblyFileName = selectedRow.Cells[AssemblyNameColumn.Name].Value.ToString();
                        string sourceFileLocation = selectedRow.Cells[FolderLocationColumn.Name].Value.ToString() + Path.DirectorySeparatorChar + assemblyFileName;
                        string targetFileLocation = targetFolderPath + Path.DirectorySeparatorChar + assemblyFileName;
                        File.Copy(sourceFileLocation, targetFileLocation, true);
                    }

                    MessageBox.Show("Successfully copied " + MainDataGridView.SelectedRows.Count + " assembly(s) to folder!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void ExitMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                this.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void LoadDataGridView()
        {
            var assemblyInfoCollection = GetAssemblySubDirectories().SelectMany(oneAssemblySubDirectory =>
                                           Directory.EnumerateDirectories(oneAssemblySubDirectory).Select(oneAssemblyFolder =>
                                           {
                                               DirectoryInfo assemblyFolderInfo = new DirectoryInfo(oneAssemblyFolder);
                                               string[] assemblyFolderParts = assemblyFolderInfo.Name.Split('_');

                                               return new
                                               {
                                                   AssemblyName = assemblyFolderInfo.EnumerateFiles().Where(oneFileInfo =>
                                                       oneFileInfo.Extension.Equals(".dll", StringComparison.InvariantCultureIgnoreCase) ||
                                                       oneFileInfo.Extension.Equals(".exe", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(),
                                                   Version = assemblyFolderParts.Length == 3 ? assemblyFolderParts[0] : assemblyFolderParts[0] + "_" + assemblyFolderParts[1],
                                                   PublicKeyToken = assemblyFolderParts.Length == 3 ? assemblyFolderParts[2] : assemblyFolderParts[3],
                                                   ProcessorArchitecture = GetProcessorArchitecture(assemblyFolderInfo.Parent.Parent.Name),
                                                   Culture = assemblyFolderParts.Length == 3 ? assemblyFolderParts[1] : assemblyFolderParts[2],
                                                   FolderLocation = assemblyFolderInfo
                                               };
                                           }));

            MainDataGridView.Rows.Clear();
            foreach (var assemblyInfo in assemblyInfoCollection)
            {
                MainDataGridView.Rows.Add(assemblyInfo.AssemblyName, assemblyInfo.Version, assemblyInfo.PublicKeyToken,
                    assemblyInfo.ProcessorArchitecture, assemblyInfo.Culture, assemblyInfo.FolderLocation);
            }
        }

        private string GetProcessorArchitecture(string selectedAssemblySubDirectorType)
        {
            string processorArchitecture = string.Empty;
            AssemblySubDirectorType assemblySubDirectorType = (AssemblySubDirectorType)Enum.Parse(typeof(AssemblySubDirectorType), selectedAssemblySubDirectorType);
            
            switch (assemblySubDirectorType)
            {
                case AssemblySubDirectorType.GAC:
                    break;
                case AssemblySubDirectorType.GAC_32:
                    processorArchitecture = "x86";
                    break;
                case AssemblySubDirectorType.GAC_64:
                    processorArchitecture = "x64";
                    break;
                case AssemblySubDirectorType.GAC_MSIL:
                    processorArchitecture = "MSIL";
                    break;
                default:
                    break;
            }

            return processorArchitecture;
        }

        private IEnumerable<string> GetAssemblySubDirectories()
        {
            IEnumerable<string> assemblySubDirectories = null;
            string windowsFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.Windows);

            List<string> assemblyDirectoryList = new List<string>()
            {
                windowsFolderPath + @"\assembly",
                windowsFolderPath + @"\Microsoft.NET\assembly"
            };

            assemblySubDirectories = assemblyDirectoryList.SelectMany(oneAssemblyDirectory =>
                                        Enum.GetNames(typeof(AssemblySubDirectorType)).Select(oneAssemblySubDirectoryType =>
                                            oneAssemblyDirectory + Path.DirectorySeparatorChar + oneAssemblySubDirectoryType).Where(oneAssemblySubDirectory =>
                                                Directory.Exists(oneAssemblySubDirectory)).SelectMany(oneAssemblySubDirectory =>
                                                    Directory.EnumerateDirectories(oneAssemblySubDirectory)));

            return assemblySubDirectories;
        }

        private enum AssemblySubDirectorType
        {
            GAC,
            GAC_32,
            GAC_64,
            GAC_MSIL
        }               
    }
}
